//
//  HttpRequest.m
//  RedballBar
//
//  Created by Faith on 2019/1/9.
//  Copyright © 2019 Faith. All rights reserved.
//

#import "HttpRequest.h"
#import <sys/utsname.h>

@implementation HttpRequest

static id _instance = nil;

+ (instancetype)getInstance {
    return [[self alloc] init];
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });
    return _instance;
}

- (instancetype)init {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super init];
        AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];
        [manager startMonitoring];
        [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
            switch (status) {
                case AFNetworkReachabilityStatusUnknown:
                {
                    // 未知网络
                    NSLog(@"未知网络");
                }
                    break;
                case AFNetworkReachabilityStatusNotReachable:
                {
                    // 无法联网
                    NSLog(@"无法联网");
                    [Utils setLocalStorage:@"networkState" value:@"1"];
                }
                    break;
                case AFNetworkReachabilityStatusReachableViaWiFi:
                {
                    // WIFI
                    NSLog(@"当前在WIFI网络下");
                    if([[Utils getLocalStorage:@"networkState"] isEqualToString:@"1"]) {
                        [Utils setLocalStorage:@"networkState" value:@""];
                        [[NSNotificationCenter defaultCenter] postNotificationName:@"NETWORK_STATE_CHANGE" object:@"OK"];
                    }
                }
                    break;
                case AFNetworkReachabilityStatusReachableViaWWAN:
                {
                    // 蜂窝数据
                    NSLog(@"当前使用蜂窝数据");
                    if([[Utils getLocalStorage:@"networkState"] isEqualToString:@"1"]) {
                        [Utils setLocalStorage:@"networkState" value:@""];
                        [[NSNotificationCenter defaultCenter] postNotificationName:@"NETWORK_STATE_CHANGE" object:@"OK"];
                    }
                }
            }
        }];
    });
    return _instance;
}

/**
 * 获取URL数据
 */
- (void)getUrl:(NSString *)requestUrl parameters:(NSDictionary *)parameters success:(void (^)(id))success {
    [self getUrl:requestUrl parameters:parameters success:success failure:nil unauthorized:nil];
}

/**
 * 获取URL数据
 */
- (void)getUrl:(NSString *)requestUrl parameters:(NSDictionary *)parameters success:(void (^)(id))success failure:(void (^)(NSError *))failure {
    [self getUrl:requestUrl parameters:parameters success:success failure:failure unauthorized:nil];
}

/**
 * 获取URL数据
 */
- (void)getUrl:(NSString *)requestUrl parameters:(NSDictionary *)parameters success:(void (^)(id))success failure:(void (^)(NSError *))failure unauthorized:(void (^)(void))unauthorized {
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.requestSerializer.timeoutInterval = 30;
    // 读取本地token
    NSString *token = [Utils getUserToken];
    if(token!=nil) {
        [manager.requestSerializer setValue:[NSString stringWithFormat:@"%@", token] forHTTPHeaderField:@"satoken"];
    }
    manager.requestSerializer.HTTPShouldUsePipelining = YES;
    manager.requestSerializer.HTTPShouldHandleCookies = NO;
    [manager.requestSerializer setCachePolicy:NSURLRequestReloadIgnoringCacheData];
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/html", @"text/plain", nil];
    requestUrl = [NSString stringWithFormat:@"%@%@", [requestUrl hasPrefix:@"https://"] || [requestUrl hasPrefix:@"http://"] ? @"" : BASE_URL, requestUrl];
    NSLog(@"\n请求方式: GET\n请求地址: %@\n请求数据: %@\n头部数据: %@", requestUrl, parameters, manager.requestSerializer.HTTPRequestHeaders);
    [manager GET:requestUrl parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSError *error;
        id responseData = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments|NSJSONReadingFragmentsAllowed error:&error];
        if(error) {
            NSLog(@"解析返回数据出错: %@", error);
            if (failure) {
                failure(error);
            }
            return;
        }
        responseData = [HttpRequest processDictionary:responseData];
        if(responseData[@"code"]!=nil) {
            if([responseData[@"code"] intValue]==200) {
                NSLog(@"服务端返回数据: %@", responseData);
                if (success) {
                    success(responseData);
                }
            } else if([responseData[@"code"] intValue]==401) {
                NSLog(@"会话过期或未登录, 请重新登陆");
                // 清除本地缓存数据
                [Utils removeUserData];
                [[NSNotificationCenter defaultCenter] postNotificationName:@"logoutComplate" object:nil];
                if (unauthorized) {
                    unauthorized();
                } else {
                    // 没有定义身份验证失败回调，使用failure回调
                    if (failure) {
                        NSDictionary *userInfo = @{
                            NSLocalizedDescriptionKey: responseData[@"msg"]
                        };
                        NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:[responseData[@"code"] intValue] userInfo:userInfo];
                        failure(error);
                    }
                }
            } else {
                NSLog(@"服务端出错: %@", responseData[@"msg"]);
                if (failure) {
                    NSDictionary *userInfo = @{
                        NSLocalizedDescriptionKey: responseData[@"msg"]
                    };
                    NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:404 userInfo:userInfo];
                    failure(error);
                }
            }
        } else { /// 其他返回的结果
            NSLog(@"服务端返回数据: %@", responseData);
            success(responseData);
        }
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"错误发生: %@", error);
        if (failure) {
            failure(error);
        }
    }];
}

/**
 * 发送表单请求
 */
- (void)postForm:(NSString *)requestUrl parameters:(NSDictionary *)parameters success:(void (^)(id))success {
    [self postForm:requestUrl parameters:parameters loading:nil success:success failure:nil unauthorized:nil];
}

/**
 * 发送表单请求
 */
- (void)postForm:(NSString *)requestUrl parameters:(NSDictionary *)parameters success:(void (^)(id))success failure:(void (^)(NSError *))failure {
    [self postForm:requestUrl parameters:parameters loading:nil success:success failure:failure unauthorized:nil];
}

/**
 * 发送表单请求
 */
- (void)postForm:(NSString *)requestUrl parameters:(NSDictionary *)parameters loading:(NSString*)loading success:(void (^)(id))success {
    [self postForm:requestUrl parameters:parameters loading:loading success:success failure:nil unauthorized:nil];
}

/**
 * 发送表单请求
 */
- (void)postForm:(NSString *)requestUrl parameters:(NSDictionary *)parameters loading:(NSString*)loading success:(void (^)(id))success failure:(void (^)(NSError *))failure {
    [self postForm:requestUrl parameters:parameters loading:loading success:success failure:failure unauthorized:nil];
}

/**
 * 发送表单请求
 */
- (void)postForm:(NSString *)requestUrl parameters:(NSDictionary *)parameters loading:(NSString*)loading success:(void (^)(id))success failure:(void (^)(NSError *))failure unauthorized:(void (^)(void))unauthorized {
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.requestSerializer.timeoutInterval = 30;
    manager.requestSerializer.HTTPShouldUsePipelining = YES;
    manager.requestSerializer.HTTPShouldHandleCookies = NO;
    NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:[NSString stringWithFormat:@"%@%@", [requestUrl hasPrefix:@"https://"] || [requestUrl hasPrefix:@"http://"] ? @"" : BASE_URL, requestUrl] parameters:parameters error:nil];
    // 读取本地token
    NSString *token = [Utils getUserToken];
    if(token!=nil) {
        [request setValue:[NSString stringWithFormat:@"%@", token] forHTTPHeaderField:@"satoken"];
    }
    AFHTTPResponseSerializer *responseSerializer = [AFHTTPResponseSerializer serializer];
    responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/html", nil];
    manager.responseSerializer = responseSerializer;
    NSLog(@"\n请求方式: POST\n请求地址: %@\n请求数据: %@\n头部数据: %@", [NSString stringWithFormat:@"%@%@", [requestUrl hasPrefix:@"https://"] || [requestUrl hasPrefix:@"http://"] ? @"" : BASE_URL, requestUrl], parameters, request.allHTTPHeaderFields);
    [SVProgressHUD showWithStatus:loading ? loading : @"加载中..."];
    [[manager dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        //[SVProgressHUD dismiss];
        if (!error) {
            NSError *error;
            id responseData = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:&error];
            if(error) {
                NSLog(@"解析返回数据出错: %@", error);
            }
            responseData = [HttpRequest processDictionary:responseData];
            if (success) {
                NSInteger code = [responseData[@"code"] intValue];
                if(code==200) {
                    NSLog(@"服务端返回数据: %@", responseData);
                    success(responseData);
                } else if([responseData[@"code"] intValue]==401) {
                    // 清除本地缓存数据
                    [Utils removeUserData];
                    [[NSNotificationCenter defaultCenter] postNotificationName:@"logoutComplate" object:nil];
                    if (unauthorized) {
                        unauthorized();
                    } else {
                        // 没有定义身份验证失败回调，使用failure回调
                        if (failure) {
                            NSDictionary *userInfo = @{
                                NSLocalizedDescriptionKey: responseData[@"msg"]
                            };
                            NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:[responseData[@"code"] intValue] userInfo:userInfo];
                            failure(error);
                        }
                    }
                } else {
                    [SVProgressHUD showImage:[UIImage imageNamed:@""] status:responseData[@"msg"]];
                }
            }
        } else {
            if (failure) {
                failure(error);
            }
        }
    }] resume];
}

/**
 * 发送JSON请求
 */
- (void)postJson:(NSString *)requestUrl object:(NSDictionary *)object success:(void (^)(id))success {
    [self postJson:requestUrl object:object success:success failure:nil unauthorized:nil];
}

/**
 * 发送JSON请求
 */
- (void)postJson:(NSString *)requestUrl object:(NSDictionary *)object success:(void (^)(id))success failure:(void (^)(NSError *))failure {
    [self postJson:requestUrl object:object success:success failure:failure unauthorized:nil];
}

/**
 * 发送JSON请求
 */
- (void)postJson:(NSString *)requestUrl object:(NSDictionary *)object success:(void (^)(id))success failure:(void (^)(NSError *))failure unauthorized:(void (^)(void))unauthorized {
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.requestSerializer.timeoutInterval = 30;
    manager.requestSerializer.HTTPShouldUsePipelining = YES;
    manager.requestSerializer.HTTPShouldHandleCookies = NO;
    NSMutableURLRequest *request = [[AFJSONRequestSerializer serializer] requestWithMethod:@"POST" URLString:[NSString stringWithFormat:@"%@%@", [requestUrl hasPrefix:@"https://"] || [requestUrl hasPrefix:@"http://"] ? @"" : BASE_URL, requestUrl] parameters:object error:nil];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    // 读取本地token
    NSString *token = [Utils getUserToken];
    if(token!=nil) {
        [request setValue:[NSString stringWithFormat:@"%@", token] forHTTPHeaderField:@"satoken"];
    }
    AFHTTPResponseSerializer *responseSerializer = [AFHTTPResponseSerializer serializer];
    responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/html", nil];
    manager.responseSerializer = responseSerializer;
    NSLog(@"\n请求方式: POST\n请求地址: %@\n请求数据: %@\n头部数据: %@", [NSString stringWithFormat:@"%@%@", [requestUrl hasPrefix:@"https://"] || [requestUrl hasPrefix:@"http://"] ? @"" : BASE_URL, requestUrl], object, request.allHTTPHeaderFields);
    [[manager dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        if (!error) {
            NSError *error;
            id responseData = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:&error];
            if(error) {
                NSLog(@"解析返回数据出错: %@", error);
            }
            responseData = [HttpRequest processDictionary:responseData];
            if (success) {
                NSInteger code = [responseData[@"code"] intValue];
                if(code==200) {
                    success(responseData);
                } else if([responseData[@"code"] intValue]==401) {
                    // 清除本地缓存数据
                    [Utils removeUserData];
                    [[NSNotificationCenter defaultCenter] postNotificationName:@"logoutComplate" object:nil];
                    if (unauthorized) {
                        unauthorized();
                    } else {
                        // 没有定义身份验证失败回调，使用failure回调
                        if (failure) {
                            NSDictionary *userInfo = @{
                                NSLocalizedDescriptionKey: responseData[@"msg"]
                            };
                            NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:[responseData[@"code"] intValue] userInfo:userInfo];
                            failure(error);
                        }
                    }
                } else {
                    [SVProgressHUD showImage:[UIImage imageNamed:@""] status:responseData[@"msg"]];
                }
            }
        } else {
            [SVProgressHUD showImage:[UIImage imageNamed:@""] status:error.userInfo.description];
            if (failure) {
                failure(error);
            }
        }
    }] resume];
}

/**
 * 发送上传文件请求
 */
- (void)postFile:(NSString *)requestUrl name:(NSString *)name fileName:(NSString *)fileName data:(NSData *)data success:(void (^)(id))success {
    [self postFile:requestUrl name:name fileName:fileName data:data success:success failure:nil unauthorized:nil];
}

/**
 * 发送上传文件请求
 */
- (void)postFile:(NSString *)requestUrl name:(NSString *)name fileName:(NSString *)fileName data:(NSData *)data success:(void (^)(id))success failure:(void (^)(NSError *))failure {
    [self postFile:requestUrl name:name fileName:fileName data:data success:success failure:failure unauthorized:nil];
}

/**
 * 发送上传文件请求
 */
- (void)postFile:(NSString *)requestUrl name:(NSString *)name fileName:(NSString *)fileName data:(NSData *)data success:(void (^)(id))success failure:(void (^)(NSError *))failure unauthorized:(void (^)(void))unauthorized {
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.requestSerializer.timeoutInterval = 3600;
    manager.requestSerializer.HTTPShouldUsePipelining = YES;
    manager.requestSerializer.HTTPShouldHandleCookies = NO;
    NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:[NSString stringWithFormat:@"%@%@", [requestUrl hasPrefix:@"https://"] || [requestUrl hasPrefix:@"http://"] ? @"" : BASE_URL, requestUrl] parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        [formData appendPartWithFileData:data name:name fileName:fileName mimeType:@"image/png"];
    } error:nil];
    // 读取本地token
    NSString *token = [Utils getUserToken];
    if(token!=nil) {
        [request setValue:[NSString stringWithFormat:@"%@", token] forHTTPHeaderField:@"satoken"];
    }
    AFHTTPResponseSerializer *responseSerializer = [AFHTTPResponseSerializer serializer];
    responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/html", nil];
    manager.responseSerializer = responseSerializer;
    NSLog(@"\n请求方式: POST Multipart\n请求地址: %@\n头部数据: %@", [NSString stringWithFormat:@"%@%@", [requestUrl hasPrefix:@"https://"] || [requestUrl hasPrefix:@"http://"] ? @"" : BASE_URL, requestUrl], request.allHTTPHeaderFields);
    //[SVProgressHUD showWithStatus:@"加载中..."];
    [[manager uploadTaskWithStreamedRequest:request progress:nil completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        //[SVProgressHUD dismiss];
        if (!error) {
            NSError *error;
            id responseData = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:&error];
            NSLog(@"返回数据: %@", responseData);
            if(error) {
                NSLog(@"解析返回数据出错: %@", error);
            }
            responseData = [HttpRequest processDictionary:responseData];
            if (success) {
                NSInteger code = [responseData[@"code"] intValue];
                if(code==200) {
                    success(responseData);
                } else if([responseData[@"code"] intValue]==401) {
                    // 清除本地缓存数据
                    [Utils removeUserData];
                    [[NSNotificationCenter defaultCenter] postNotificationName:@"logoutComplate" object:nil];
                    if (unauthorized) {
                        unauthorized();
                    } else {
                        // 没有定义身份验证失败回调，使用failure回调
                        if (failure) {
                            NSDictionary *userInfo = @{
                                NSLocalizedDescriptionKey: responseData[@"msg"]
                            };
                            NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:[responseData[@"code"] intValue] userInfo:userInfo];
                            failure(error);
                        }
                    }
                } else {
                    [SVProgressHUD showImage:[UIImage imageNamed:@""] status:responseData[@"msg"]];
                }
            }
        } else {
            [SVProgressHUD showImage:[UIImage imageNamed:@""] status:error.userInfo.description];
            if (failure) {
                failure(error);
            }
        }
    }] resume];
}







/**
 * 获取URL数据
 */
- (void)putUrl:(NSString *)requestUrl parameters:(NSDictionary *)parameters success:(void (^)(id))success {
    [self putUrl:requestUrl parameters:parameters success:success failure:nil unauthorized:nil];
}

/**
 * 获取URL数据
 */
- (void)putUrl:(NSString *)requestUrl parameters:(NSDictionary *)parameters success:(void (^)(id))success failure:(void (^)(NSError *))failure {
    [self putUrl:requestUrl parameters:parameters success:success failure:failure unauthorized:nil];
}

/**
 * 获取URL数据
 */
- (void)putUrl:(NSString *)requestUrl parameters:(NSDictionary *)parameters success:(void (^)(id))success failure:(void (^)(NSError *))failure unauthorized:(void (^)(void))unauthorized {
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.requestSerializer.timeoutInterval = 30;
    // 读取本地token
    NSString *token = [Utils getUserToken];
    if(token!=nil) {
        [manager.requestSerializer setValue:[NSString stringWithFormat:@"%@", token] forHTTPHeaderField:@"satoken"];
    }
    manager.requestSerializer.HTTPShouldUsePipelining = YES;
    manager.requestSerializer.HTTPShouldHandleCookies = NO;
    [manager.requestSerializer setCachePolicy:NSURLRequestReloadIgnoringCacheData];
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/html", @"text/plain", nil];
    requestUrl = [NSString stringWithFormat:@"%@%@", [requestUrl hasPrefix:@"https://"] || [requestUrl hasPrefix:@"http://"] ? @"" : BASE_URL, requestUrl];
    NSLog(@"\n请求方式: PUT\n请求地址: %@\n请求数据: %@\n头部数据: %@", requestUrl, parameters, manager.requestSerializer.HTTPRequestHeaders);
    [manager PUT:requestUrl parameters:parameters success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSError *error;
        id responseData = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments|NSJSONReadingFragmentsAllowed error:&error];
        if(error) {
            NSLog(@"解析返回数据出错: %@", error);
            if (failure) {
                failure(error);
            }
            return;
        }
        responseData = [HttpRequest processDictionary:responseData];
        if(responseData[@"code"]!=nil) {
            if([responseData[@"code"] intValue]==200) {
                NSLog(@"服务端返回数据: %@", responseData);
                if (success) {
                    success(responseData);
                }
            } else if([responseData[@"code"] intValue]==401) {
                NSLog(@"会话过期或未登录, 请重新登陆");
                // 清除本地缓存数据
                [Utils removeUserData];
                [[NSNotificationCenter defaultCenter] postNotificationName:@"logoutComplate" object:nil];
                if (unauthorized) {
                    unauthorized();
                } else {
                    // 没有定义身份验证失败回调，使用failure回调
                    if (failure) {
                        NSDictionary *userInfo = @{
                            NSLocalizedDescriptionKey: responseData[@"msg"]
                        };
                        NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:[responseData[@"code"] intValue] userInfo:userInfo];
                        failure(error);
                    }
                }
            } else {
                NSLog(@"服务端出错: %@", responseData[@"msg"]);
                if (failure) {
                    NSDictionary *userInfo = @{
                        NSLocalizedDescriptionKey: responseData[@"msg"]
                    };
                    NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:404 userInfo:userInfo];
                    failure(error);
                }
            }
        } else { /// 其他返回的结果
            NSLog(@"服务端返回数据: %@", responseData);
            success(responseData);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"错误发生: %@", error);
        if (failure) {
            failure(error);
        }
    }];
}

/**
 * 处理反序列化对象中值为nil的情况
 */
+ (NSDictionary *)processDictionary:(NSDictionary *)dictionary {
    NSMutableDictionary *processedDict = [NSMutableDictionary dictionary];
    for (NSString *key in dictionary.allKeys) {
        id value = dictionary[key];
        if ([value isKindOfClass:[NSDictionary class]]) {
            NSDictionary *nestedDict = (NSDictionary *)value;
            processedDict[key] = [self processDictionary:nestedDict];
        } else if ([value isKindOfClass:[NSArray class]]) {
            NSMutableArray *nestedArray = [[NSMutableArray alloc] initWithArray:value];
            for(int i=0;i<nestedArray.count; i++) {
                id value = nestedArray[i];
                if([value isKindOfClass:[NSDictionary class]]) {
                    nestedArray[i] = [self processDictionary:value];
                } else {
                    if ([value isEqual:[NSNull null]]) {
                        nestedArray[i] = @"";
                    } else {
                        nestedArray[i] = value;
                    }
                }
            }
            processedDict[key] = [nestedArray mutableCopy];
        } else {
            if ([value isEqual:[NSNull null]]) {
                processedDict[key] = @"";
            } else {
                processedDict[key] = value;
            }
        }
    }
    
    return processedDict;
}


@end
